/**
 * @author Chengzi Xu
 */

package cn.edu.sjtu.stap.sdg;

import cn.edu.sjtu.stap.cfg.CfgCall;
import cn.edu.sjtu.stap.cfg.CfgEntry;
import cn.edu.sjtu.stap.cfg.CfgNode;
import cn.edu.sjtu.stap.graph.GraphNode;

/**
 * This class mainly provide the wrap function to the SDGbuilder. As the
 * SDGbuilder will use all the nodes from Cfg.
 * 
 * @author xucz
 * 
 */
public abstract class SdgNode extends GraphNode {

    private static long nodeCount = 0;    

    private static final long serialVersionUID = 1L;

    private SdgNodeKind kind;

    private CfgNode cfgNode;

    private String sourceLocation;

    public SdgNode(SdgNodeKind kind) {
        super(++nodeCount);
        setKind(kind);
    }

    /**
     * warp the specific CfgNode to SdgNode
     * 
     * @param cfgNode
     * @return
     */
    public static SdgNode createSdgNode(CfgNode cfgNode) {
        SdgNode result = null;

        if (cfgNode instanceof CfgEntry) {
            SdgNode sdgEntry = new SdgEntry(SdgNodeKind.ENTRY);
            sdgEntry.cfgNode = cfgNode;
            result = sdgEntry;
        } else if (cfgNode instanceof CfgCall) {
            SdgNode sdgMethod = new SdgCallSite(SdgNodeKind.CALLSITE);
            sdgMethod.cfgNode = cfgNode;
            result = sdgMethod;
        } else {
            SdgNode sdgMethod = new SdgStatement(SdgNodeKind.STATEMENT);
            sdgMethod.cfgNode = cfgNode;
            result = sdgMethod;
        }

        return result;
    }

    public void setCfgNode(CfgNode input) {
        cfgNode = input;
        makeSourceLocation();
    }

    public void setKind(SdgNodeKind kind) {
        if (null == kind) {
            throw new NullPointerException("Node kind should not be null!");
        }
        this.kind = kind;
    }

    public String getSourceLocation() {
        return sourceLocation;
    }

    public String getName() {
        return kind.getName();
    }

    public CfgNode getCfgNode() {
        return cfgNode;
    }

    private void makeSourceLocation() {
        if (cfgNode == null) {
            return;
        }
        sourceLocation = cfgNode.getASTNode().sourceStart() + "|"
                + cfgNode.getASTNode().sourceEnd();
    }

    @Override
    public String toString() {
        StringBuffer s = new StringBuffer();
        s.append("(Sdg Node Id: ");
        s.append(this.getId());
        s.append(", Source Location: ");
        s.append(this.getCfgNode() == null ? null : this.getCfgNode()
                .getLocationInfo());
        s.append(", Name: ");
        s.append(this.getCfgNode() == null ? null : this.getCfgNode().getKind()
                .getName());
        s.append(", Content: ");
        if (cfgNode != null)
            s.append(cfgNode.getASTNode() == null ? null : cfgNode.getASTNode()
                    .toString());
        else
            s.append(cfgNode.getASTNode() == null ? null : cfgNode.getASTNode()
                    .toString());

        s.append(")\n");
        return s.toString();
    }
}